package linuxbox.filelib.logic;

import java.io.*;
import java.util.*;

import org.apache.log4j.*;
import linuxbox.*;
import linuxbox.admin.bean.*;
import linuxbox.admin.logic.*;
import linuxbox.filelib.bean.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: </p>
 * @author unascribed
 * @version 1.0
 The <b>permission</b> allows user to view the attributes of the object, user can see the object exists in the library.
 The <b>Read</b> permission allows user to download the object. Only useful for file.
 The <b>Write</b> permission allows add/delete/update/change permissions on an object, useful for both folder/file.
 The <b>Take Ownership</b> permission allows user to take the ownership of the object. The owner of the object can do anything on the object.
 *
 *
 * To test:
 *     1. Add Folder/File
 *        1.1 Own parent folder readonly
 *        1.2 Own parent folder not readonly
 *        1.3 Other's parent folder, Allow write, readonly
 *        1.4 Other's parent folder, Allow write, not readonly
 *        1.5 Other's parent folder, not Allow write
 *     2. Update Folder/File
 *        2.1

 */

public class FileLibHome
{
  protected static Logger logger = Logger.getLogger(FileLibHome.class.getName());
  public final static int ROOT = 0;

  //own attributes
  public final static long READONLY = 0x0000000000000001L;
  public final static long INHERIT = 0x0000000000000002L;

  //attributes for access rights in permission list
  public final static long READ_ALLOW = 0x0000000000000001L;
  public final static long READ_DENY = 0x0000000000000002L;
  public final static long WRITE_ALLOW = 0x0000000000000004L;
  public final static long WRITE_DENY = 0x0000000000000008L;
  public final static long BROWSE_ALLOW = 0x0000000000000010L;
  public final static long BROWSE_DENY = 0x0000000000000020L;
  public final static long TAKEOWNERSHIP_ALLOW = 0x0000000000000040L;
  public final static long TAKEOWNERSHIP_DENY = 0x0000000000000080L;

  protected static FileLibHome staticInstance = null;

  public static FileLibHome getInstance()
  {
    if (staticInstance == null)
    {
      staticInstance = new FileLibHome();
    }
    return staticInstance;
  }

  private FileLibHome()
  {}

  public FileLibEntry add()
  {
    FileLibBean bean = new FileLibBean();
    FileLibEntry entry = null;
    try
    {
      bean.create();
      entry = (FileLibEntry) bean.getObject();
    }
    catch (Exception e)
    {
      logger.error("Error create filelib entry:", e);
    }
    return (FileLibEntry) bean.getObject();
  }

  public void remove(FileLibEntry entry)
  {
    FileLibBean bean = new FileLibBean();
    bean.setObject(entry);
    try
    {
      bean.remove();
    }
    catch (Exception e)
    {
      logger.error("Error remove filelib entry:", e);
    }
  }

  public void remove(int id)
  {
    FileLibBean bean = new FileLibBean();
    FileLibEntry entry = new FileLibEntry();
    entry.setId(id);
    bean.setObject(entry);
    remove(entry);
  }

  public void update(FileLibEntry entry)
  {
    FileLibBean bean = new FileLibBean();
    bean.setObject(entry);
    try
    {
      bean.store();
    }
    catch (Exception e)
    {
      logger.error("Error update filelib entry:", e);
    }
  }

  public FileLibEntry get(int id)
  {
    FileLibBean bean = new FileLibBean();
    FileLibEntry entry = new FileLibEntry();
    entry.setId(id);
    bean.setObject(entry);
    try
    {
      bean.load();
    }
    catch (Exception e)
    {
      logger.error("Error get filelib entry:", e);
      return null;
    }
    return entry;
  }

  //return true:  empty
  //       false: still have child
  public boolean deleteFolder(int userid, FileLibEntry curFolder) throws
      Exception
  {
    boolean isEmpty = true;
    Collection col = getEntries(userid, curFolder.getID(), "name", true);
    Iterator it = col.iterator();
    while (it != null && it.hasNext())
    {
      FileLibEntry child = (FileLibEntry) it.next();
      if (child != null)
      {
        if (child.getIsfolder())
        {
          if (!deleteFolder(userid, child))
          {
            isEmpty = false;
          }
        }
        else
        {
          if (!deleteFile(userid, child))
          {
            isEmpty = false;
          }
        }
      }
    }
    if (isEmpty)
    {
      remove(curFolder);

    }
    return isEmpty;
  }

  //return true:  file is deleted
  //       false: deleted failed
  public boolean deleteFile(int userid, FileLibEntry entry) throws Exception
  {
    boolean deleted = true;
    if (!checkAccessRights(userid, entry, WRITE_ALLOW))
    {
      return false;
    }

    String SavedFilename = BoxStatic.HOME_DIR + BoxStatic.DOWNLOAD_FILE_DIR +
        File.separator + entry.getID();
    File file = new File(SavedFilename);
    logger.warn("Deleting file: " + SavedFilename + " Userid=" + userid);
    if (file.exists())
    {
      deleted = file.delete();
    }
    else
    {
      logger.debug("File: " + SavedFilename + " not exist");

    }
    if (deleted)
    {
      logger.debug("Deleted file: " + SavedFilename + " Userid=" + userid);
    }
    else
    {
      logger.debug("Fail to deleting file: " + SavedFilename + " Userid=" +
                   userid);
    }
    if (deleted)
    {
      remove(entry);
    }
    return deleted;
  }

  public Collection getFolders(int userid, int curFolder, long right) throws
      Exception
  {
    FileLibBean bean = new FileLibBean();
    StringBuffer sql = new StringBuffer();
    sql.append("parent=");
    sql.append(curFolder);
    sql.append(" and isfolder=1 ");

    Collection col = bean.findBySql(sql.toString());
    filterByAccessRights(col, userid, right);
    return col;
  }

  public boolean hasChildFolder(int userid, int curFolder, long right) throws
      Exception
  {
    FileLibBean bean = new FileLibBean();
    StringBuffer sql = new StringBuffer();
    sql.append("parent=");
    sql.append(curFolder);
    sql.append(" and isfolder=1 ");

    Collection col = bean.findBySql(sql.toString());
    filterByAccessRights(col, userid, right);
    return col.size() > 0;
  }

  public boolean hasChild(int curFolder) throws Exception
  {
    FileLibBean bean = new FileLibBean();
    StringBuffer sql = new StringBuffer();
    sql.append("parent=");
    sql.append(curFolder);

    Collection col = bean.findBySql(sql.toString());
    return col.size() > 0;
  }

  public Collection getEntries(int userid, int curFolder, String SORTBY,
                               boolean sortAsc) throws Exception
  {
    FileLibBean bean = new FileLibBean();
    StringBuffer sql = new StringBuffer();
    sql.append("parent=");
    sql.append(curFolder);
    sql.append(" and isfolder=1 ");

    Collection col = bean.findBySql(sql.toString());
    sql = new StringBuffer();
    sql.append("parent=");
    sql.append(curFolder);
    sql.append(" and isfolder=0 ");
    if (bean.isValidFieldName(SORTBY))
    {
      sql.append(" order by ");
      sql.append(SORTBY);
      if (sortAsc)
      {
        sql.append(" ASC ");
      }
      else
      {
        sql.append(" DESC ");
      }
    }
    else
    {
      logger.warn("Passing an invalid sortby fieldname:" + SORTBY);
    }
    Collection col1 = bean.findBySql(sql.toString());
    col.addAll(col1);

    //default to BROWSE right
    filterByAccessRights(col, userid, BROWSE_ALLOW);
    return col;
  }

  public boolean checkAccessRights(int userid, FileLibEntry entry, long right) throws
      Exception
  {
    //Check readonly flag of the entry should be done by somewhere else
    /*
            if (((right & WRITE_ALLOW) != 0)
            && ((entry.getAttributes() & READONLY) != 0))
          return false;
     */
    if (entry.getOwnerid() == userid)
    {
      return true;
    }

//TOTO_XX    if user is administrator
    Collection col = getPermissionList(entry);
    Iterator it = col.iterator();
    while (it != null && it.hasNext())
    {
      PermissionEntry permission = (PermissionEntry) it.next();
      if (permission != null)
      {
        logger.error("BBBBBBB userid:" + permission.getUserid());
        if (userid == permission.getUserid()
            ||
            (permission.getIsgroup() && isUserInGroup(userid, permission.getUserid())))
        {
          logger.error("BBBBBBB check right: " + right);
          long denyRight = right >> 1;
          if ( (permission.getPermission() & denyRight) != 0)
          {
            return false;
          }
          if ( (permission.getPermission() & right) != 0)
          {
            return true;
          }
        }
      }
    }
    //default to false
    logger.error("BBBBBBB default to false");
    return false;
  }

  public String getPathString(int id)
  {
    if (id == ROOT || id == -1) //ROOT's parent is -1
    {
      return "/";
    }
    FileLibBean bean = new FileLibBean();
    return bean.getPathString(id);
  }

  public int[] getParentFolders(int id)
  {
    FileLibBean bean = new FileLibBean();
    return bean.getParentFolders(id);
  }

  public boolean updatePermissions(FileLibEntry objEntry, String[] permissions) throws
      Exception
  {
    PermissionEntryBean bean = new PermissionEntryBean();
    if ( (objEntry.getAttributes() & INHERIT) != 0)
    {

      //if inherit, no permissions defined for itself
      return bean.updatePermissions(objEntry.getID(), null);
    }
    else
    {
      return bean.updatePermissions(objEntry.getID(), permissions);
    }
  }

  protected boolean isUserInGroup(int userid, int groupid)
  {
    //TODO_XX
    if (groupid == 0) //Everyone
    {
      return true;
    }
    return false;
  }

  /**
   * search
   *
   * @param criteria SearchEntry
   * @param userID int
   * @return Iterator
   */
  public Iterator search(SearchEntry criteria, int userID) throws Exception
  {
    if (criteria == null)
      return null;

    StringBuffer sql = new StringBuffer();
    boolean bFirst = true;
    if ((criteria.searchName || criteria.searchFilename || criteria.searchFoldername )
        && (criteria.searchText != null && criteria.searchText.length() >0))
    {
      sql.append("((");
      if (criteria.searchName || criteria.searchFoldername)
      {
        sql.append(" ( name like '%");
        sql.append(criteria.searchText);
        sql.append("%')");
        bFirst = false;
      }
      if (criteria.searchFilename)
      {
        if (!bFirst)
          sql.append(" or ");
        sql.append(" ( filename like '%");
        sql.append(criteria.searchText);
        sql.append("%')");
      }
      sql.append(")");
      if (!criteria.searchFoldername)
        sql.append(" and isfolder=0 ");
      sql.append(")");
      bFirst = false;
    }
    if (criteria.searchByTime)
    {
      if (!bFirst)
        sql.append(" and ");
      java.sql.Timestamp tmp = new java.sql.Timestamp(criteria.modifiedFrom.getTimeInMillis());

      sql.append("( lastmodifiedtime >='");
      sql.append(tmp.toString());
      sql.append("' and lastmodifiedtime <='");
      tmp.setTime(criteria.modifiedTo.getTimeInMillis());
      sql.append(tmp.toString());
      sql.append("')");
      bFirst = false;
    }

    if (criteria.searchBySize)
    {
      if (!bFirst)
        sql.append(" and ");

      sql.append("( size ");
      if (criteria.isSizeGreater)
        sql.append(">=");
      else
        sql.append("<=");
      long size = Long.parseLong(criteria.size);
      if (criteria.sizeUnit == SearchEntry.SIZEUNIT_KBYTES )
        size *= 1024;
      if (criteria.sizeUnit == SearchEntry.SIZEUNIT_MBYTES )
        size *= 1024*1024;
      sql.append(size);
      sql.append(")");
    }

    FileLibBean bean = new FileLibBean();
    if (bean.isValidFieldName(criteria.sortBy))
    {
      sql.append(" order by ");
      sql.append(criteria.sortBy);
      if (criteria.sortAsc)
      {
        sql.append(" ASC ");
      }
      else
      {
        sql.append(" DESC ");
      }
    }
    else
    {
      logger.warn("Passing an invalid sortby fieldname:" + criteria.sortAsc);
    }
    Collection col = bean.findBySql(sql.toString());

    //default to BROWSE right
    filterByAccessRights(col, userID, BROWSE_ALLOW);
    return col.iterator();
  }

  public Collection getPermissionList(FileLibEntry entry) throws Exception
  {
    if (entry.getID() == ROOT)
    {
      return getPermissionList(ROOT);
    }

    //look for the closest parent that has inherit flag set or use the root
    while (entry.getID() != ROOT && ( (entry.getAttributes() & INHERIT) != 0))
    {
      int id = entry.getParent();
      entry = get(id);
    }
    return getPermissionList(entry.getID());
  }

  protected Collection getPermissionList(int entryid) throws Exception
  {
    PermissionEntryBean bean = new PermissionEntryBean();
    return bean.getPermissionList(entryid);
  }

  protected void filterByAccessRights(Collection col, int userid, long right) throws
      Exception
  {
    if (col != null && col.size() > 0 && right != 0)
    {
      Collection removeCol = new ArrayList();
      Iterator it = col.iterator();
      while (it.hasNext())
      {
        FileLibEntry entry = (FileLibEntry) it.next();
        if (!checkAccessRights(userid, entry, right))
        {
          removeCol.add(entry);
        }
      }
      if (removeCol.size() > 0)
      {
        col.removeAll(removeCol);
      }
    }
  }

  /**
   * getPermissionString(PermissionEntry entry)
   *
   * @return String
   */
  public static String getPermissionString(PermissionEntry entry) throws
      Exception
  {
    if (entry == null)
    {
      return "";
    }
    StringBuffer str = new StringBuffer();
    UserManager um = UserManager.getInstance();
    if (entry.getIsgroup())
    {
      //TODO_XX: "Group for every one"
      str.append("Group-");
      if (entry.getUserid() == 0)
      {
        str.append("Everyone");
      }
      else
      {
        UserGrpKey grpKey = new UserGrpKey(entry.getUserid());
        UserGrpObject grp = um.getUserGrp(grpKey);
        if (grp == null)
        {
          return "";
        }
        str.append(grp.getName());
      }
    }
    else
    {
      User user = um.getUser(entry.getUserid());
      if (user == null)
      {
        return "";
      }

      str.append("User-");
      str.append(user.getLastName());
      str.append(",");
      str.append(user.getFirstName());
      str.append("(");
      str.append(user.getLoginID());
      str.append(")");
    }

    str.append(": ");
    if (entry.getPermission() == 0)
    {
      return str.toString();
    }
    boolean first = true;
    if ( (entry.getPermission() & FileLibHome.BROWSE_ALLOW) != 0)
    {
      str.append("Allow Browse");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.BROWSE_DENY) != 0)
    {
      str.append("Deny Browse");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.READ_ALLOW) != 0)
    {
      if (!first)
      {
        str.append("/");
      }
      str.append("Allow Read");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.READ_DENY) != 0)
    {
      if (!first)
      {
        str.append("/");
      }
      str.append("Deny Read");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.WRITE_ALLOW) != 0)
    {
      if (!first)
      {
        str.append("/");
      }
      str.append("Allow Write");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.WRITE_DENY) != 0)
    {
      if (!first)
      {
        str.append("/");
      }
      str.append("Deny Write");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.TAKEOWNERSHIP_ALLOW) != 0)
    {
      if (!first)
      {
        str.append("/");
      }
      str.append("Allow Take Ownership");
      first = false;
    }
    if ( (entry.getPermission() & FileLibHome.TAKEOWNERSHIP_DENY) != 0)
    {
      if (!first)
      {
        str.append("/");
      }
      str.append("Deny Take Ownership");
      first = false;
    }
    return str.toString();
  }
}
